﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tomahawk.Runtime.Canvas.Sprite;
using System.Xml.Serialization;
using Tomahawk.Runtime.Logic.UI.Components;

namespace Tomahawk.Runtime.Logic.UI
{
    /// <summary>
    /// This controls shows a button that can be focused and clicked by the user
    /// </summary>
    public class XUIButton : XUIPlaceableControl
    {

        #region "Serializable Properties"

        [XmlElement("UnselectedImage")]
        public ImageComponent imageUnselected;
        
        [XmlElement("SelectedImage")]
        public ImageComponent imageSelected;
        
        [XmlElement("PressedImage")]
        public ImageComponent imagePressed;

        [XmlElement("Text")]
        public TextComponent textComponent;

        #endregion

        /// <summary>
        /// Control Initialization
        /// </summary>
        protected override void OnInitialize()
        {
            base.OnInitialize();

            //
            // image components
            //

            this.imagePressed.Initialize();
            this.imageSelected.Initialize();
            this.imageUnselected.Initialize();

            // text component
            this.textComponent.Initialize();

            //show / hide the right sprite
            this.changeState(ControlStates.Unselected);

            //copy position and size to sprites
            this.passPositionToSprites();

        }

        #region "State Management"

        /// <summary>
        /// Available states for a button
        /// </summary>
        protected enum ControlStates
        {
            Unselected,
            Selected,
            Pressed
        }

        protected ControlStates currentState = ControlStates.Unselected;

        /// <summary>
        /// Change control state
        /// </summary>
        protected void changeState(ControlStates newState)
        {
            //assign
            this.currentState = newState;

            //set visibility
            this.setSpriteVisibility();
            this.setTextColor();
        }


        #endregion

        #region "Visibility"

        /// <summary>
        /// Make the appropiate sprite visible, and hide the rest
        /// </summary>
        private void setSpriteVisibility()
        {
            switch (this.currentState)
            {
                case ControlStates.Pressed:
                    this.imagePressed.SetVisibility(true);
                    this.imageSelected.SetVisibility(false);
                    this.imageUnselected.SetVisibility(false);
                    break;
                case ControlStates.Selected:
                    this.imagePressed.SetVisibility(false);
                    this.imageSelected.SetVisibility(true);
                    this.imageUnselected.SetVisibility(false);
                    break;
                case ControlStates.Unselected:
                    this.imagePressed.SetVisibility(false);
                    this.imageSelected.SetVisibility(false);
                    this.imageUnselected.SetVisibility(true);
                    break;
            }
        }

        /// <summary>
        /// Sets the appropiate text color, upon the current state
        /// </summary>
        private void setTextColor()
        {
            switch (this.currentState)
            {
                case ControlStates.Pressed: 
                    this.textComponent.SetFontColor(ref this.textComponent.TextStyle.PressedColor);
                    break;
                case ControlStates.Unselected: 
                    this.textComponent.SetFontColor(ref this.textComponent.TextStyle.DefaultColor);
                    break;
                case ControlStates.Selected:
                    this.textComponent.SetFontColor(ref this.textComponent.TextStyle.SelectedColor);
                    break;
            }
        }

        /// <summary>
        /// Controls visibility changes
        /// </summary>
        protected override void OnChangeVisibility(bool newValue)
        {
            base.OnChangeVisibility(newValue);

            if (!newValue)
            {
                this.imagePressed.SetVisibility(false);
                this.imageSelected.SetVisibility(false);
                this.imageUnselected.SetVisibility(false);
                this.textComponent.SetVisibility(false);
            }
            else
            {
                this.setSpriteVisibility();
                this.setTextColor();
            }
        }

        #endregion

        #region "Positioning"

        /// <summary>
        /// Handle a position change
        /// </summary>
        protected override void OnPositionChange()
        {
            base.OnPositionChange();
            this.passPositionToSprites();
        }

        /// <summary>
        /// Copy the control position to the sprites
        /// </summary>
        private void passPositionToSprites()
        {
            this.imagePressed.SetPosition(ref this.renderRect);
            this.imageSelected.SetPosition(ref this.renderRect);
            this.imageUnselected.SetPosition(ref this.renderRect);
            this.textComponent.SetPosition(ref this.renderRect);
        }

        #endregion

        #region "Focus handling"

        protected override void OnFocus()
        {
            base.OnFocus();
            this.changeState(ControlStates.Selected);
        }

        protected override void OnUnfocus()
        {
            base.OnUnfocus();
            this.changeState(ControlStates.Unselected);
        }

        #endregion

        #region "Button Pressed Event"

        float pressedLeftTime = 0;

        /// <summary>
        /// Handle this event to respond to press on this button control
        /// </summary>
        public event ControlUserActivation ButtonPressed;

        /// <summary>
        /// Handle user activation of the control
        /// </summary>
        protected override void OnUserActivate()
        {
            base.OnUserActivate();

            //set the pressed state
            this.changeState(ControlStates.Pressed);

            //enable ticking
            this.UpdateRequired = true;

            //assign some pressed time
            this.pressedLeftTime = 0.1f;
            
            //call the event
            if (ButtonPressed != null) ButtonPressed(this);
        }

        /// <summary>
        /// Update the pressed animation on the button
        /// </summary>
        private void handlePressedTime(float elapsedTime)
        {
            //count back until no more pressed time left
            pressedLeftTime -= elapsedTime;
            if (pressedLeftTime < 0)
            {
                pressedLeftTime = 0;
                //change state back to selected/unselected
                if (this.Focused)
                    this.changeState(ControlStates.Selected);
                else
                    this.changeState(ControlStates.Unselected);
                //no more ticking required
                this.UpdateRequired = false;
            }
        }

        #endregion

        /// <summary>
        /// Control update. 
        /// </summary>
        protected override void OnUpdate(float elapsedTime)
        {
            base.OnUpdate(elapsedTime);

            //pressed animation
            if (this.currentState == ControlStates.Pressed)
                handlePressedTime(elapsedTime);
        }

        /// <summary>
        /// Destruction handling
        /// </summary>
        public override void OnBeforeDestroy()
        {
            base.OnBeforeDestroy();

            this.imageSelected.Destroy();
            this.imagePressed.Destroy();
            this.imageUnselected.Destroy();
            this.textComponent.Destroy();
        }

        #region "Readyness"

        /// <summary>
        /// Returns true when all the resource dependant objects are ready
        /// </summary>
        protected override bool checkResourcesReady()
        {
            return base.checkResourcesReady() &&
                this.imagePressed.IsReady() &&
                this.imageSelected.IsReady() &&
                this.imageUnselected.IsReady() &&
                this.textComponent.IsReady();
        }

        #endregion

    }

}
